<?php
/**
 * 处理推荐商品, 返回商品的 product_tag_ids
 * Author: lyun
 * Date: 2018/7/26
 * Created by Panxsoft.
 */

namespace App\Services\Repositories\Product;


use App\Http\Requests\App\RecommendProductV2IndexRequest;
use App\Models\Panx\BodyPosition;
use App\Models\Panx\Category;
use App\Models\Panx\CategoryDescription;
use App\Models\Panx\Product;
use App\Models\Panx\ProductTag;
use App\Models\Panx\SkinDetector;
use App\Models\Store\HmSkinRecord;
use App\Models\Store\Store;
use App\Models\Store\WaxSkinRecord;
use App\Models\Customer\Language;
use App\Services\Presenters\HmSkinData;
use App\Services\Presenters\WaxSkinData;
use App\Services\Utils\ApiChecker;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Http\Request;

class RecommendProductV2Repository
{
    use ApiChecker;

    protected $product;

    public function __construct()
    {
        $this->product = new Product();
    }

    /**
     * @param int $skin_detector_id
     * @param int $type_skin_record_id
     * @return array
     * @throws \App\Exceptions\ApiAbstractException
     */
    public function getTagIds(int $skin_detector_id, int $type_skin_record_id): array
    {
        if ($skin_detector_id === SkinDetector::ID_WAX) {

            return $this->getProductTagIdsByWax($skin_detector_id, $type_skin_record_id);

        } else if ($skin_detector_id === SkinDetector::ID_HM) {

            return $this->getProductTagIdsByHm($skin_detector_id);

        } else {
            return [];
        }
    }

    /**
     * @deprecated - 通过商品 whereHas 查询 body position ids 无需这样查询
     *
     * 通过会美肤质检测记录对应的身体部位找到对应的商品id
     *
     * @param Request|RecommendProductV2IndexRequest $request
     * @return array
     * @throws \Exception
     */
    public function getProductIdsForBodyPosition(Request $request): array
    {
        if ((int)$request->skin_detector_id === SkinDetector::ID_HM) {

            $hm_skin_record = (new HmSkinRecord)->find($request->type_skin_record_id);
                $this->checkItemExist($hm_skin_record,trans('admin.hm_skin_test_record'));

            $body_position = (new BodyPosition)->find($hm_skin_record->position);
                $this->checkItemExist($body_position,trans('admin.body_parts'));

            return $body_position->products->pluck('id')->all();
        } else {
            return [];
        }
    }

    /**
     * @param int $skin_detector_id
     * @param int $type_skin_record_id
     * @return int|null
     * @throws \App\Exceptions\ApiAbstractException
     */
    public function getBodyPositionId(int $skin_detector_id, int $type_skin_record_id):? int
    {
        if ($skin_detector_id === SkinDetector::ID_HM) {
            $hm_skin_record = (new HmSkinRecord)->find($type_skin_record_id);
                $this->checkItemExist($hm_skin_record,trans('admin.hm_skin_test_record'));

            $body_position_id = BodyPosition::HM_POSITION_BODY_POSITION_MAP[$hm_skin_record->position];
        } else {
            // WAX图像测肤，会推荐所有部位的商品
            $body_position_id = null;
        }

        return $body_position_id;
    }

    /**
     * @param int $skin_detector_id
     * @param int $type_skin_record_id
     * @return int|null
     * @throws \App\Exceptions\ApiAbstractException
     */
    public function getRecommendCategoryId(int $skin_detector_id, int $type_skin_record_id): ?int
    {
        if ($skin_detector_id === SkinDetector::ID_HM) {
            $hm_skin_record = (new HmSkinRecord)->find($type_skin_record_id);
                $this->checkItemExist($hm_skin_record, trans('admin.hm_skin_test_record'));

            if (HmSkinData::checkAllLabelIsGood($hm_skin_record)) {
                return Category::getBasicCare()->id ?? null;
            } else {
                return null;
            }
        } elseif ($skin_detector_id === SkinDetector::ID_WAX) {
            $wax_skin_record = (new WaxSkinRecord)->find($type_skin_record_id);
                $this->checkItemExist($wax_skin_record, trans('admin.wax_skin_test_record'));

            if (WaxSkinData::checkLevelSortIsGood($wax_skin_record)) {
                return Category::getBasicCare()->id ?? null;
            } else {
                return null;
            }
        } else {
            return null;
        }
    }

    /**
     * @param Collection $recommend_products
     * @return Collection
     */
    public function transformRecommendProducts(Collection $recommend_products): Collection
    {
        $group_recommend_products = $recommend_products->groupBy('category_id');
        $language_code = app()->getLocale();
        $language_id = Language::getLanguageIds()[$language_code] ?? Language::LANGUAGE_ID_CN;
        $category_descriptions = CategoryDescription::where(compact('language_id'))
            ->pluck('name', 'category_id')
            ->toArray();

        $group_recommend_products->transform(function (Collection $group_products, $category_id) use($category_descriptions){
            /** @var Category $category */
            $category = $group_products->first()->category;

            $data = [
                'category_id'   => $category_id,
                'category_name' => $category_descriptions[$category_id] ?? null,
                'priority'      => $category->priority,
                'icon_active'   => $category->icon_active,
                'icon'          => $category->icon,
                'products'      => $group_products,
            ];

            $group_products->makeHidden('category');

            return $data;
        });

        return $group_recommend_products->sortByDesc('priority')->values();
    }

    /**
     * @param int $skin_detector_id
     * @param int $type_skin_record_id
     * @return mixed
     * @throws \App\Exceptions\ApiAbstractException
     */
    private function getProductTagIdsByWax(int $skin_detector_id, int $type_skin_record_id): array
    {
        $waxSkinRecord = (new WaxSkinRecord)->find($type_skin_record_id);
            $this->checkItemExist($waxSkinRecord, trans('admin.wax_skin_test_record'));

        // itemsid 与 SkinDetectionItem item_id 是对应的
        $item_id = $waxSkinRecord->itemsid;

        $product_tag_ids =  (new ProductTag)
            ->whereHas('skinDetectionItems', function(Builder $query) use($skin_detector_id,$item_id) {
                return $query->where('skin_detector_id', $skin_detector_id)
                    ->where('item_id',$item_id);
            })
            ->pluck('id')
            ->all();

        return $product_tag_ids;
    }

    /**
     * @param int $skin_detector_id
     * @return array
     */
    private function getProductTagIdsByHm(int $skin_detector_id): array
    {
        $product_tag_ids =  (new ProductTag)
            ->whereHas('skinDetectionItems', function(Builder $query) use($skin_detector_id) {
                return $query->where('skin_detector_id', $skin_detector_id);
            })
            ->pluck('id')
            ->all();

        return $product_tag_ids; // [2,3,4]
    }

    /**
     * @param Store $store
     * @param array $tag_ids
     * @param int|null $sex
     * @param int|null $body_position_id
     * @param int|null $category_id
     *
     * @return Product[]|Collection
     */
    public function recommendStoreProducts(Store $store, array $tag_ids,
                                           ?int $sex, ?int $body_position_id, ?int $category_id): Collection
    {
        $recommend_products = $this->product
            ->filterSex($sex)
            ->filterOnShelf()
            ->filterStoreProductType($store, Product::STORE_CUSTOMER_PRODUCT)
            ->whereNotIn($this->product->getQualifiedKeyName(), ProductRepository::getStoreCustomerDeletedProductIds($store))
            ->whereHas('productTags', function (Builder $query) use ($tag_ids) {
                $query->whereIn((new ProductTag)->getQualifiedKeyName(), $tag_ids);
            })
            ->filterBodyPosition($body_position_id)
            ->filterCategory($category_id)
            ->whereHas('category')
            ->with('thumbImage', 'productTags', 'category', 'brand')
            ->inRandomOrder()
            ->limit(rand(5, 10))
            ->get();

        return $recommend_products;
    }
}



